Completed
Push — master ( 59ad2d...412337 )
by Xu
293:44 queued 253:04
created

MetisMenu.show   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 38
rs 8.439
1
/*
2
 * metismenu - v2.0.3
3
 * A jQuery menu plugin
4
 * https://github.com/onokumus/metisMenu
5
 *
6
 * Made by Osman Nuri Okumus
7
 * Under MIT License
8
 */
9
10
(function($) {
11
  'use strict';
12
13
  function transitionEnd() {
14
    var el = document.createElement('mm');
15
16
    var transEndEventNames = {
17
      WebkitTransition: 'webkitTransitionEnd',
18
      MozTransition: 'transitionend',
19
      OTransition: 'oTransitionEnd otransitionend',
20
      transition: 'transitionend'
21
    };
22
23
    for (var name in transEndEventNames) {
24
      if (el.style[name] !== undefined) {
25
        return {
26
          end: transEndEventNames[name]
27
        };
28
      }
29
    }
30
    return false;
31
  }
32
33
  $.fn.emulateTransitionEnd = function(duration) {
34
    var called = false;
35
    var $el = this;
36
    $(this).one('mmTransitionEnd', function() {
37
      called = true;
38
    });
39
    var callback = function() {
40
      if (!called) {
41
        $($el).trigger($transition.end);
42
      }
43
    };
44
    setTimeout(callback, duration);
45
    return this;
46
  };
47
48
  var $transition = transitionEnd();
49
  if (!!$transition) {
50
    $.event.special.mmTransitionEnd = {
51
      bindType: $transition.end,
52
      delegateType: $transition.end,
53
      handle: function(e) {
54
        if ($(e.target).is(this)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $(e.target).is(this) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
55
          return e.
56
          handleObj.
57
          handler.
58
          apply(this, arguments);
59
        }
60
      }
61
    };
62
  }
63
64
  var MetisMenu = function(element, options) {
65
    this.$element = $(element);
66
    this.options = $.extend({}, MetisMenu.DEFAULTS, options);
67
    this.transitioning = null;
68
69
    this.init();
70
  };
71
72
  MetisMenu.TRANSITION_DURATION = 350;
73
74
  MetisMenu.DEFAULTS = {
75
    toggle: true,
76
    doubleTapToGo: false,
77
    activeClass: 'active',
78
    collapseClass: 'collapse',
79
    collapseInClass: 'in',
80
    collapsingClass: 'collapsing'
81
  };
82
83
  MetisMenu.prototype.init = function() {
84
    var $this = this;
85
    var activeClass = this.options.activeClass;
86
    var collapseClass = this.options.collapseClass;
87
    var collapseInClass = this.options.collapseInClass;
88
89
    this
90
      .$element
91
      .find('li.' + activeClass)
92
      .has('ul')
93
      .children('ul')
94
      .addClass(collapseClass + ' ' + collapseInClass);
95
96
    this
97
      .$element
98
      .find('li')
99
      .not('.' + activeClass)
100
      .has('ul')
101
      .children('ul')
102
      .addClass(collapseClass);
103
104
    //add the 'doubleTapToGo' class to active items if needed
105
    if (this.options.doubleTapToGo) {
106
      this
107
        .$element
108
        .find('li.' + activeClass)
109
        .has('ul')
110
        .children('a')
111
        .addClass('doubleTapToGo');
112
    }
113
114
    this
115
      .$element
116
      .find('li')
117
      .has('ul')
118
      .children('a')
119
      .on('click.metisMenu', function(e) {
120
        var self = $(this);
121
        var $parent = self.parent('li');
122
        var $list = $parent.children('ul');
123
        e.preventDefault();
124
125
        if ($parent.hasClass(activeClass) && !$this.options.doubleTapToGo) {
126
          $this.hide($list);
127
        } else {
128
          $this.show($list);
129
        }
130
131
        //Do we need to enable the double tap
132
        if ($this.options.doubleTapToGo) {
133
          //if we hit a second time on the link and the href is valid, navigate to that url
134
          if ($this.doubleTapToGo(self) && self.attr('href') !== '#' && self.attr('href') !== '') {
135
            e.stopPropagation();
136
            document.location = self.attr('href');
137
            return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
138
          }
139
        }
140
      });
141
  };
142
143
  MetisMenu.prototype.doubleTapToGo = function(elem) {
144
    var $this = this.$element;
145
    //if the class 'doubleTapToGo' exists, remove it and return
146
    if (elem.hasClass('doubleTapToGo')) {
147
      elem.removeClass('doubleTapToGo');
148
      return true;
149
    }
150
    //does not exists, add a new class and return false
151
    if (elem.parent().children('ul').length) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if elem.parent().children("ul").length is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
152
      //first remove all other class
153
      $this
154
        .find('.doubleTapToGo')
155
        .removeClass('doubleTapToGo');
156
      //add the class on the current element
157
      elem.addClass('doubleTapToGo');
158
      return false;
159
    }
160
  };
161
162
  MetisMenu.prototype.show = function(el) {
163
    var activeClass = this.options.activeClass;
164
    var collapseClass = this.options.collapseClass;
165
    var collapseInClass = this.options.collapseInClass;
166
    var collapsingClass = this.options.collapsingClass;
167
    var $this = $(el);
168
    var $parent = $this.parent('li');
169
    if (this.transitioning || $this.hasClass(collapseInClass)) {
170
      return;
171
    }
172
173
    $parent.addClass(activeClass);
174
175
    if (this.options.toggle) {
176
      this.hide($parent.siblings().children('ul.' + collapseInClass));
177
    }
178
179
    $this
180
      .removeClass(collapseClass)
181
      .addClass(collapsingClass)
182
      .height(0);
183
184
    this.transitioning = 1;
185
    var complete = function() {
186
      $this
187
        .removeClass(collapsingClass)
188
        .addClass(collapseClass + ' ' + collapseInClass)
189
        .height('');
190
      this.transitioning = 0;
191
    };
192
    if (!$transition) {
193
      return complete.call(this);
194
    }
195
    $this
196
      .one('mmTransitionEnd', $.proxy(complete, this))
197
      .emulateTransitionEnd(MetisMenu.TRANSITION_DURATION)
198
      .height($this[0].scrollHeight);
199
  };
200
201
  MetisMenu.prototype.hide = function(el) {
202
    var activeClass = this.options.activeClass;
203
    var collapseClass = this.options.collapseClass;
204
    var collapseInClass = this.options.collapseInClass;
205
    var collapsingClass = this.options.collapsingClass;
206
    var $this = $(el);
207
208
    if (this.transitioning || !$this.hasClass(collapseInClass)) {
209
      return;
210
    }
211
212
    $this.parent('li').removeClass(activeClass);
213
    $this.height($this.height())[0].offsetHeight;
0 ignored issues
show
introduced by
The result of the property access to $this.height($this.height()).0.offsetHeight is not used.
Loading history...
214
215
    $this
216
      .addClass(collapsingClass)
217
      .removeClass(collapseClass)
218
      .removeClass(collapseInClass);
219
220
    this.transitioning = 1;
221
222
    var complete = function() {
223
      this.transitioning = 0;
224
      $this
225
        .removeClass(collapsingClass)
226
        .addClass(collapseClass);
227
    };
228
229
    if (!$transition) {
230
      return complete.call(this);
231
    }
232
    $this
233
      .height(0)
234
      .one('mmTransitionEnd', $.proxy(complete, this))
235
      .emulateTransitionEnd(MetisMenu.TRANSITION_DURATION);
236
  };
237
238
  function Plugin(option) {
239
    return this.each(function() {
240
      var $this = $(this);
241
      var data = $this.data('mm');
242
      var options = $.extend({},
243
        MetisMenu.DEFAULTS,
244
        $this.data(),
245
        typeof option === 'object' && option
246
      );
247
248
      if (!data) {
249
        $this.data('mm', (data = new MetisMenu(this, options)));
250
      }
251
      if (typeof option === 'string') {
252
        data[option]();
253
      }
254
    });
255
  }
256
257
  var old = $.fn.metisMenu;
258
259
  $.fn.metisMenu = Plugin;
260
  $.fn.metisMenu.Constructor = MetisMenu;
261
262
  $.fn.metisMenu.noConflict = function() {
263
    $.fn.metisMenu = old;
264
    return this;
265
  };
266
267
})(jQuery);
268